# @Time    : 2022/8/30 15:59
# @Author  : ysh
# @File    : base_dal
# @Software: PyCharm
from tortoise import Tortoise, Model
from typing import List

from common.result.err_msg import FailErr
from common.result.result_code import MysqlCont
from utils.sql_app.raw_sql import sql_get_data
from common import logger
from common.result.error import SqlErr


class BaseDal:

    def __init__(self, model=None):
        self.__Model = model
        self.model = model()

    async def get_by_id(self, o_id: int) -> dict:
        try:
            obj = await self.model.get(pk=o_id).first()
        except Exception as e:
            logger.error(f"[MYSQL] 数据查询失败：{e}")
            raise SqlErr(err_obj=MysqlCont.SelectErr, msg_obj=FailErr, message="查询数据失败！")
        return obj

    async def get_one_info(self, filters: dict) -> dict:
        try:
            obj = await self.model.filter(**filters).first().values()
        except Exception as e:
            logger.error(f"[MYSQL] 数据查询失败：{e}")
            raise SqlErr(err_obj=MysqlCont.SelectErr, msg_obj=FailErr, message="查询数据失败！")
        return obj

    async def get_one_obj_info(self, filters: dict) -> dict:
        try:
            obj = await self.model.filter(**filters).first()
        except Exception as e:
            logger.error(f"[MYSQL] 数据查询失败：{e}")
            raise SqlErr(err_obj=MysqlCont.SelectErr, msg_obj=FailErr, message="查询数据失败！")
        return obj

    async def get_data_by_condition(self,  filters=dict, exclueds=None, values=tuple(), order_by=('-id',),  *args, **kwargs) -> List[object]:
        exclueds = exclueds if type(exclueds) == dict else dict()
        filters = filters if type(filters) == dict else dict()
        values = tuple(values) if isinstance(values, (tuple, list, set)) else tuple()
        try:
            if values:
                datas = await self.model.filter(**filters).exclude(**exclueds).order_by(*order_by).values(*values)
            else:
                datas = await self.model.filter(**filters).exclude(**exclueds).order_by(*order_by).all()
        except Exception as e:
            logger.error(f"[MYSQL] 数据查询失败：{e}")
            raise SqlErr(err_obj=MysqlCont.SelectErr, msg_obj=FailErr, message="查询数据失败！")
        return datas

    async def get_order_data_by_order_id(self, filters=dict, exclueds=None,  order_by=('-id',),  *args, **kwargs)-> List[dict]:
        exclueds = exclueds if type(exclueds) == dict else dict()
        filters = filters if type(filters) == dict else dict()
        datas = await self.model.filter(**filters).exclude(**exclueds).order_by(*order_by).first()
        return datas

    async def get_info_filter(self, filters=dict, exclueds=None, values=tuple(), order_by=('-id',),  *args, **kwargs) -> List[dict]:
        exclueds = exclueds if type(exclueds) == dict else dict()
        filters = filters if type(filters) == dict else dict()
        values = tuple(values) if isinstance(values, (tuple, list, set)) else tuple()
        try:
            datas = await self.model.filter(**filters).exclude(**exclueds).order_by(*order_by).values(*values)
        except Exception as e:
            logger.error(f"[MYSQL] 数据查询失败：{e}")
            raise SqlErr(err_obj=MysqlCont.SelectErr, msg_obj=FailErr, message="查询数据失败！")
        return datas

    async def update_info_by_filter(self, filters=None, excludes=None, updates=None, db_select=None, **kwargs):
        """
        base manager 根据条件更新数据库的参数
        update info

        :param filters: 查询条件
        :param db_select: 为数据库分离做准备
        :param excludes: 查询条件
        :param updates: 更新的内容
        :return:
        """
        filters = filters if type(filters) == dict else dict()

        excludes = excludes if type(excludes) == dict else dict()

        updates = updates if type(updates) == dict else dict()

        if len(filters) == 0 and len(excludes) == 0:
            return None
        if len(updates) == 0:
            return None
        try:
            k_objects = await self.model.filter(**filters).exclude(**excludes).update(**updates)
        except Exception as e:
            logger.error(f"[MYSQL] 数据更新失败：{e}")
            raise SqlErr(err_obj=MysqlCont.UpdateErr, msg_obj=FailErr, message="更新数据失败！")
        return k_objects

    async def create_one_obj(self, create_data: dict, *args, **kwargs):
        create_data = create_data if type(create_data) == dict else dict()
        try:
            create_obj = await self.model.create(**create_data)
        except Exception as e:
            logger.error(f"[MYSQL] 数据创建失败：{e}")
            raise SqlErr(err_obj=MysqlCont.CreateErr, msg_obj=FailErr, message="创建数据失败！")

        return create_obj

    async def orm_raw_sql(self, sql_text) -> List[dict]:
        # 只能查询这个model的数据
        try:
            result = await self.model.raw(sql_text)
        except Exception as e:
            logger.error(f"[MYSQL] 语句执行失败：{e}")
            raise SqlErr(err_obj=MysqlCont.SelectErr, msg_obj=FailErr, message="查询数据失败！")
        return result

    async def raw_sql(self, sql_text, sql_arg=None) -> List[dict]:
        try:
            result = await sql_get_data(sql_text, args=sql_arg)
        except Exception as e:
            logger.error(f"[MYSQL] 语句执行失败：{e}")
            raise SqlErr(err_obj=MysqlCont.SelectErr, msg_obj=FailErr, message="查询数据失败！")
        return result

    async def create_many_obj(self, create_data: List[dict]):
        assert create_data, SqlErr(err_obj=MysqlCont.CreateErr, msg_obj=FailErr, message="批量插入请传入有效数据！")
        create_data = [self.__Model(**data) for data in create_data]
        try:
            create_obj = await self.model.bulk_create(create_data)
        except Exception as e:
            logger.error("[Mysql] 批量创建失败-{}".format(e))
            raise SqlErr(err_obj=MysqlCont.CreateErr, msg_obj=FailErr, message="批量插入数据失败！")

        return create_obj
